<script setup lang="ts">
import { useControlWebsocket, useDeviceWebsocket } from '@/hooks'
import { SESSION } from '@/utils/storage'
import type { WebSocketStatus } from '@vueuse/core'
import type { WatchHandle } from 'vue'

const deviceDataWsStatus = ref<WebSocketStatus>('CONNECTING')

const router = useRouter()

const canvasRef = ref<HTMLCanvasElement | null>(null)

let watchStatus: WatchHandle

let deviceWsClose: (code?: number, reason?: string) => void

let animationFrameId: number | null = null

const renderImage = (base64Image: string) => {
  if (!canvasRef.value) return
  const ctx = canvasRef.value.getContext('2d')
  if (!ctx) return

  const binary = atob(base64Image)
  const array = new Uint8Array(binary.length)
  for (let i = 0; i < binary.length; i++) {
    array[i] = binary.charCodeAt(i)
  }
  const blob = new Blob([array], { type: 'image/jpeg' })
  const url = URL.createObjectURL(blob)

  createImageBitmap(blob).then((bitmap) => {
    ctx.clearRect(0, 0, canvasRef.value!.width, canvasRef.value!.height)
    ctx.drawImage(bitmap, 0, 0, canvasRef.value!.width, canvasRef.value!.height)
    URL.revokeObjectURL(url)
  })
}

const { send, status } = useControlWebsocket({
  onMessage: (response) => {
    if (response?.status === 'success') {
      if (!response.data?.ws_url) {
        ElMessage.error('未获取到 gait_collector websocket 地址')
        return
      }
      SESSION.set('gait_collector_ws_url', response.data.ws_url)
      enableGaitCollectorData()
    }
  },
  onAlreadyConnected: () => {
    enableGaitCollectorData()
  },
})

const enableGaitCollectorData = () => {
  const url = SESSION.get('gait_collector_ws_url') || ''
  const { open, close, status } = useDeviceWebsocket(url, {
    deviceName: 'gait_collector',
    onMessage: (collectorResponse) => {
      if (collectorResponse.type === 'device_data') {
        if (animationFrameId) cancelAnimationFrame(animationFrameId)
        animationFrameId = requestAnimationFrame(() => {
          const image = collectorResponse?.data?.image || ''
          renderImage(image)
        })
      }
    },
    connectOnMount: false,
    disConnectOnDestroy: true,
  })
  deviceWsClose = close
  watchStatus = watchEffect(() => {
    deviceDataWsStatus.value = status.value
  })
  open()
}

const enableGaitCollectorDevice = () => {
  send(
    JSON.stringify({
      command: 'start_device',
      device_name: 'gait_collector',
      token: SESSION.get('access_token') || '',
    }),
  )
}

const disableGaitCollectorDevice = () => {
  send(
    JSON.stringify({
      command: 'stop_device',
      device_name: 'gait_collector',
      token: SESSION.get('access_token') || '',
    }),
  )
}

const testOver = () => {
  router.push('/videoInteractive')
}

const reconnectWebsockets = () => {
  if (deviceWsClose) {
    deviceWsClose()
  }
  if (watchStatus) {
    watchStatus.stop()
  }

  if (status.value === 'CLOSED') {
    enableGaitCollectorDevice()
  } else if (deviceDataWsStatus.value === 'CLOSED') {
    enableGaitCollectorData()
  }
}

onMounted(() => {
  enableGaitCollectorDevice()
})

onBeforeUnmount(() => {
  if (deviceWsClose) {
    deviceWsClose()
  }
  if (watchStatus) {
    watchStatus.stop()
  }
  disableGaitCollectorDevice()
  if (animationFrameId) cancelAnimationFrame(animationFrameId)
})

window.addEventListener('beforeunload', () => {
  if (deviceWsClose) {
    deviceWsClose()
  }
  if (watchStatus) {
    watchStatus.stop()
  }
  disableGaitCollectorDevice()
})
</script>

<template>
  <el-row :gutter="48" class="h-full -mr-6">
    <el-col :span="12">
      <div class="canvas-container">
        <canvas ref="canvasRef" width="800" height="600" class="canvas"></canvas>
      </div>
    </el-col>
    <el-col :span="12" class="h-full overflow-auto pr-6">
      <div class="text-brand text-3xl">连接状态：</div>
      <div
        v-if="deviceDataWsStatus === 'OPEN' && status === 'OPEN'"
        class="border border-#D1D1D1 px-12 py-16 mt-8 rounded-lg shadow text-#00BA3D text-4xl font-bold text-center"
      >
        连接成功
      </div>
      <div
        v-else-if="deviceDataWsStatus === 'CONNECTING' || status === 'CONNECTING'"
        class="border border-#D1D1D1 px-12 py-16 mt-8 rounded-lg shadow text-#00BA3D text-4xl font-bold text-center"
      >
        连接中
      </div>
      <div
        v-else-if="deviceDataWsStatus === 'CLOSED' || status === 'CLOSED'"
        class="border border-#D1D1D1 px-12 py-16 mt-8 rounded-lg shadow text-center"
      >
        <div class="text-#BF2400 text-4xl font-500">连接失败</div>
        <div class="text-brand-darker text-lg mt-4">请检查摄像头</div>
      </div>
      <div
        class="border border-#D1D1D1 text-brand text-3xl px-12 py-16 mt-8 rounded-lg shadow text-center"
      >
        请根据语音提示做出相应动作
      </div>
      <el-button
        v-if="deviceDataWsStatus === 'CLOSED'"
        type="primary"
        class="w-full py-6! mt-8"
        @click="reconnectWebsockets"
      >
        重新连接
      </el-button>
      <el-button type="primary" class="w-full py-6! mt-8" @click="testOver">测试结束</el-button>
    </el-col>
  </el-row>
</template>

<style scoped>
.canvas-container {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #000;
  padding: 20px 0;
  height: 100%;
}

.canvas {
  width: 100%;
  height: auto;
}
</style>
